package com.one.blocks.rbac.controller;

import com.one.blocks.common.request.PageRequest;
import com.one.blocks.common.response.ResponseHelper;
import com.one.blocks.common.response.WebPageResponse;
import com.one.blocks.common.response.WebResponse;
import com.one.blocks.common.util.TreeUtil;
import com.one.blocks.mvc.controller.BaseController;
import com.one.blocks.mvc.util.ScopeWebRequestHelper;
import com.one.blocks.mvc.valid.Custom;
import com.one.blocks.mvc.valid.Update;
import com.one.blocks.mvc.valid.UpdateSelective;
import com.one.blocks.rbac.controller.query.SysOrgQuery;
import com.one.blocks.rbac.controller.vo.SysOrgGrantVo;
import com.one.blocks.rbac.controller.vo.SysOrgTreeVo;
import com.one.blocks.rbac.controller.vo.SysOrgVo;
import com.one.blocks.rbac.convert.SysOrgConvert;
import com.one.blocks.rbac.domain.SysOrg;
import com.one.blocks.rbac.log.Log;
import com.one.blocks.rbac.manager.SysOrgManager;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.groups.Default;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.one.blocks.rbac.constant.RbacConstant.ScopeRequest.VALID_ORG_CHILDREN_FULL_CODE;
import static com.one.blocks.rbac.constant.RbacConstant.ScopeRequest.VALID_ORG_ID;

/**
 * @author <a href="mailto:idler41@163.con">idler41</a> created on 2023-10-25 10:43:06
 */
@Api(tags = "系统组织接口")
@RestController
@RequestMapping("/sys/org")
@Slf4j
@Validated
@Log(module = "系统组织")
public class SysOrgController extends BaseController<SysOrgManager, SysOrgConvert, SysOrg, SysOrgVo, SysOrgQuery> {

    @Autowired
    public SysOrgController(SysOrgManager manager) {
        super(manager, SysOrgConvert.INSTANCE);
    }

    @ApiOperation("查询单个系统组织")
    @PreAuthorize("sys:org:view")
    @GetMapping
    public WebResponse<SysOrgVo> get(@RequestParam Integer id) {
        return super.generalGet(id);
    }

    @ApiOperation("根据id批量查询系统组织")
    @PreAuthorize("sys:org:view")
    @GetMapping("/batch")
    public WebResponse<List<SysOrgVo>> getByIds(@Validated @NotNull @Size(min = 1, max = 100) @RequestParam("ids") Set<Integer> ids) {
        return super.generalGetIds(ids);
    }

    @ApiOperation("分页查询系统组织")
    @PreAuthorize("sys:org:view")
    @GetMapping("/page")
    public WebPageResponse<SysOrgVo> page(@Validated PageRequest request, @Validated SysOrgQuery query) {
        return super.generalPage(request, query);
    }

    @ApiOperation("添加系统组织")
    @PreAuthorize("sys:org:insert")
    @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public WebResponse<Serializable> insert(@Validated @RequestBody SysOrgVo sysOrgVo) {
        return super.generalInsert(sysOrgVo);
    }

    @ApiOperation("更新系统组织(更新所有字段)")
    @PreAuthorize("sys:org:update")
    @PutMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public WebResponse<Void> update(@Validated(Update.class) @RequestBody SysOrgVo sysOrgVo) {
        if (isNotNeedUpdateSubTree(sysOrgVo)) {
            return super.generalUpdateSelective(sysOrgVo);
        }
        // 更新所有子节点编码数据
        updateSubTree(sysOrgVo);
        return ResponseHelper.success();
    }

    @ApiOperation("更新系统组织(只更新非空字段)")
    @PreAuthorize("sys:org:update")
    @PatchMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public WebResponse<Void> updateSelective(@Validated(UpdateSelective.class) @RequestBody SysOrgVo sysOrgVo) {
        if (isNotNeedUpdateSubTree(sysOrgVo)) {
            return super.generalUpdateSelective(sysOrgVo);
        }
        // 更新所有子节点编码数据
        updateSubTree(sysOrgVo);
        return ResponseHelper.success();
    }

    @ApiOperation("根据id批量删除系统组织")
    @PreAuthorize("sys:org:delete")
    @DeleteMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public WebResponse<Void> deleteByIds(@Validated @NotNull @Size(min = 1, max = 100) @RequestBody Set<Integer> ids) {
        return super.generalDeleteByIds(ids);
    }

    @ApiOperation("根据id批量查询系统组织")
    @PreAuthorize("sys:org:view")
    @GetMapping("/tree")
    public WebResponse<List<SysOrgTreeVo>> tree(@Validated SysOrgQuery query) {
        return ResponseHelper.success(TreeUtil.buildStrictTree(convert.entityToTreeList(manager.find(convert.queryToEntity(query)))));
    }

    @ApiOperation("指定用户授权组织")
    @PreAuthorize("sys:org:grant")
    @PostMapping("/grant")
    public WebResponse<Void> grant(@Validated({Default.class, Custom.class}) @RequestBody SysOrgGrantVo sysOrgGrantVo) {
        manager.grant(sysOrgGrantVo.getOrgId(), convert.grantVoToGrantEntity(sysOrgGrantVo));
        return ResponseHelper.success();
    }

    private void updateSubTree(SysOrgVo sysOrgVo) {
        SysOrg row = ScopeWebRequestHelper.get(VALID_ORG_ID + sysOrgVo.getId(), () -> manager.get(sysOrgVo.getId()));
        if (row == null) {
            return;
        }

        // 构建树
        List<SysOrg> list = manager.findAllChildrenByFullCode(row.getFullCode());
        List<SysOrgTreeVo> tree = TreeUtil.buildStrictTree(convert.entityToTreeVoList(list));
        Map<Integer, SysOrg> map = list.stream().collect(Collectors.toMap(SysOrg::getId, i -> i));

        List<SysOrg> listToUpdate = new ArrayList<>();
        // 深度遍历更新
        TreeUtil.deptTraversal(tree, (node, stack) -> {
            SysOrg itemToUpdate, parentRow;
            if (node.getTreeId().equals(sysOrgVo.getId())) {
                // 修改当前节点
                itemToUpdate = convert.voToEntity(sysOrgVo);
                parentRow = ScopeWebRequestHelper.get(VALID_ORG_ID + sysOrgVo.getParentId(), () -> manager.get(sysOrgVo.getParentId()));
            } else {
                // 修改节点子树节点
                itemToUpdate = map.get(node.getTreeId());
                parentRow = map.get(stack.peek().getTreeId());
            }

            itemToUpdate.setLevelNum(parentRow.getLevelNum() + 1);
            itemToUpdate.setFullCode(parentRow.getFullCode() + "@" + itemToUpdate.getCode());
            listToUpdate.add(itemToUpdate);
        });
        manager.updateBatchById(listToUpdate);
    }

    private boolean isNotNeedUpdateSubTree(SysOrgVo sysOrgVo) {
        SysOrg row = ScopeWebRequestHelper.get(VALID_ORG_ID + sysOrgVo.getId(), () -> manager.get(sysOrgVo.getId()));
        if (row == null) {
            return true;
        }

        // 编码与父目录都未更改
        if (row.getParentId().equals(sysOrgVo.getParentId()) && row.getCode().equals(sysOrgVo.getCode())) {
            return true;
        }

        // 是否为叶子结点
        List<SysOrg> subTreeData = ScopeWebRequestHelper.get(VALID_ORG_CHILDREN_FULL_CODE + row.getFullCode(),
                () -> manager.findAllChildrenByFullCode(row.getFullCode()));
        return CollectionUtils.isEmpty(subTreeData);
    }
}